﻿#include "precomp.h"
#include "jcurvewidget.h"
#include "private/jcurvewidget_p.h"
#include "private/jsiftareaeditor.h"
#include "private/jbaselineshapeitem.h"
#include "jcurve.h"
#include "qwt_plot.h"
#include "qwt_date_scale_draw.h"
#include "qwt_date_scale_engine.h"
#include "qwt_abstract_legend.h"

// - class JCurveWidget -

JCurveWidget::JCurveWidget(QWidget *parent, bool zoom) :
    QWidget(parent),
    d_ptr(new JCurveWidgetPrivate(this))
{
    Q_D(JCurveWidget);
    d->init(zoom);
}

JCurveWidget::JCurveWidget(const QString &title, QWidget *parent, bool zoom) :
    QWidget(parent),
    d_ptr(new JCurveWidgetPrivate(this))
{
    Q_D(JCurveWidget);
    d->init(zoom, title);
}

JCurveWidget::~JCurveWidget()
{
    clearCurve();

    delete d_ptr;
}

JCurve *JCurveWidget::addCurve(const QString &title)
{
    Q_D(JCurveWidget);
    JCurve *curve = new JCurve(title);
    curve->setCurveStyle(d->optionWidget->curveStyle());
    curve->attach(d->plot);
    curve->setColor(randColor());
    curve->setShiftCount(100);
    d->curves.append(curve);
    autoScale();

    return curve;
}

JCurve *JCurveWidget::addCurve(const QString &title, const QPen &pen)
{
    Q_D(JCurveWidget);
    JCurve* curve = new JCurve(title);
    curve->setCurveStyle(d->optionWidget->curveStyle());
    curve->setLinePen(pen);
    curve->setColor(pen.color());
    curve->setShiftCount(100);
    d->curves.append(curve);
    curve->attach(d->plot);
    autoScale();

    return curve;
}

JCurve *JCurveWidget::addCurve(const QString &title, const QPen &pen, const QVector<QPointF> &samples)
{
    Q_D(JCurveWidget);
    JCurve* curve = new JCurve(title);
    curve->setCurveStyle(d->optionWidget->curveStyle());
    curve->setLinePen(pen.color());
    curve->attach(d->plot);
    curve->setSamples(samples);
    curve->setShiftCount(100);
    d->curves.append(curve);
    autoScale();

    return curve;
}

void JCurveWidget::removeCurve(JCurve *curve)
{
    Q_D(JCurveWidget);
    if (d->curves.contains(curve)) {
        for (int i = 0; i < d->curves.count(); ++i) {
            if (d->curves[i] == curve) {
                if (d->canvasPicker
                        &&d->canvasPicker->selectedCurve() == curve) {
                    d->canvasPicker->clearSelect();
                }
                d->curves[i]->detach();
                delete d->curves[i];
                d->curves.removeAt(i);
                break;
            }
        }
    }
}

void JCurveWidget::clearCurve()
{
    Q_D(JCurveWidget);
    if (d->canvasPicker) {
        d->canvasPicker->clearSelect();
    }
    foreach (JCurve *curve, d->curves) {
        curve->detach();
        delete curve;
    }

    d->curves.clear();
}

void JCurveWidget::autoScale()
{
    Q_D(JCurveWidget);

    //
    d->zoomer->setZoomBase();

    //
    d->plot->setAxisAutoScale(QwtPlot::xBottom);
    d->plot->setAxisAutoScale(QwtPlot::yLeft);
    //d->plot->setAxisAutoScale(QwtPlot::yRight);
}

QString JCurveWidget::title() const
{
    Q_D(const JCurveWidget);
    return d->plot->title().text();
}

void JCurveWidget::setTitle(const QString &text)
{
    Q_D(JCurveWidget);
    d->plot->setTitle(text);
    if (d->databaseEdit) {
        d->databaseEdit->setWindowTitle(QStringLiteral("数据截取编辑 [")
                                        + QString(text).remove(QRegExp("\\<.[^<>]*\\>"))
                                        + "]");
    }
}

QString JCurveWidget::curveTitle(int index) const
{
    Q_D(const JCurveWidget);
    if (index < 0 || index >= d->curves.count()) {
        return QString::null;
    }

    return d->curves.at(index)->title().text();
}

bool JCurveWidget::setCurveTitle(int index, const QString &text)
{
    Q_D(JCurveWidget);
    if (index < 0 || index >= d->curves.count()) {
        return false;
    }

    d->curves[index]->setTitle(text);

    return true;
}

JCurve *JCurveWidget::curve(int index) const
{
    Q_D(const JCurveWidget);
    if (index < 0 || index >= d->curves.count()) {
        return 0;
    }

    return d->curves.at(index);
}

QVector<JCurve *> &JCurveWidget::curves()
{
    Q_D(JCurveWidget);
    return d->curves;
}

bool JCurveWidget::enableDbClick() const
{
    Q_D(const JCurveWidget);
    return d->enableDbClick;
}

void JCurveWidget::setEnableDbClick(bool enable)
{
    Q_D(JCurveWidget);
    if (enable != d->enableDbClick) {
        d->enableDbClick = enable;
        Q_EMIT enableDbClickChanged(enable);
    }
}

bool JCurveWidget::baseLineVisible() const
{
    Q_D(const JCurveWidget);
    return d->optionWidget->isBaseLineVisible();
}

bool JCurveWidget::baseLineEnabled() const
{
    Q_D(const JCurveWidget);
    return d->optionWidget->isBaseLineEnabled();
}

bool JCurveWidget::curveStyleVisible() const
{
    Q_D(const JCurveWidget);
    return d->optionWidget->isCurveStyleVisible();
}

bool JCurveWidget::editEnabled() const
{
    Q_D(const JCurveWidget);
    return d->optionWidget->isEditEnabled();
}

bool JCurveWidget::exportVisible() const
{
    Q_D(const JCurveWidget);
    return d->optionWidget->isExportVisible();
}

void JCurveWidget::setBaseLineVisible(bool visible)
{
    Q_D(JCurveWidget);
    d->optionWidget->setBaseLineVisible(visible);
}

void JCurveWidget::setCurveStyleVisible(bool visible)
{
    Q_D(JCurveWidget);
    d->optionWidget->setCurveStyleVisible(visible);
}

void JCurveWidget::setCurveStyle(CurveStyle curveStyle)
{
    Q_D(JCurveWidget);
    d->optionWidget->setCurveStyle(curveStyle);
}

void JCurveWidget::setLegendVisible(bool visible)
{
    Q_D(JCurveWidget);
    if (d->legend) {
        d->legend->setVisible(visible);
    }
}

void JCurveWidget::setEditWidgetVisible(bool visible)
{
    Q_D(JCurveWidget);
    if (d->databaseEdit && d->optionWidget->isEditEnabled()) {
        d->databaseEdit->setVisible(visible);
    }
}

void JCurveWidget::setExportVisible(bool visible)
{
    Q_D(JCurveWidget);
    d->optionWidget->setExportVisible(visible);
}

void JCurveWidget::setBaseLineEnabled(bool enabled)
{
    Q_D(JCurveWidget);
    d->optionWidget->setBaseLineEnabled(enabled);
}

void JCurveWidget::setEditEnabled(bool enabled)
{
    Q_D(JCurveWidget);
    d->optionWidget->setEditEnabled(enabled);
    if (!enabled && d->databaseEdit && d->optionWidget->isEditEnabled()) {
        d->databaseEdit->hide();
    }
}

void JCurveWidget::setNormalScale()
{
    Q_D(JCurveWidget);
    if (d->zoomer) {
        //
    }
}

JCurveWidget::AxisXYType JCurveWidget::axisXYType() const
{
    Q_D(const JCurveWidget);
    return d->axisXYType;
}

void JCurveWidget::setAxisXYType(AxisXYType type)
{
    Q_D(JCurveWidget);
    if (type != d->axisXYType) {
        d->axisXYType = type;
        //
        switch (type) {
        case AxisXY_Time_Time:
        {
            d->plot->setAxisScaleDraw(QwtPlot::xBottom, new JTimeScaleDraw(Qt::UTC));
            d->plot->setAxisScaleDraw(QwtPlot::yLeft, new JTimeScaleDraw(Qt::UTC));
            d->picker->setTimeXAxis(true);
            if (d->zoomer) {
                d->zoomer->setTimeXAxis(true);
            }
            break;
        }
        case AxisXY_Time_Value:
        {
            d->plot->setAxisScaleDraw(QwtPlot::xBottom, new JTimeScaleDraw(Qt::UTC));
            d->plot->setAxisScaleDraw(QwtPlot::yLeft, new QwtScaleDraw());
            d->picker->setTimeXAxis(true);
            if (d->zoomer) {
                d->zoomer->setTimeXAxis(true);
            }
            break;
        }
        case AxisXY_Value_Time:
        {
            d->plot->setAxisScaleDraw(QwtPlot::xBottom, new QwtScaleDraw());
            d->plot->setAxisScaleDraw(QwtPlot::yLeft, new JTimeScaleDraw(Qt::UTC));
            d->picker->setTimeXAxis(false);
            if (d->zoomer) {
                d->zoomer->setTimeXAxis(false);
            }
            break;
        }
        case AxisXY_Value_Value:
        {
            d->plot->setAxisScaleDraw(QwtPlot::xBottom, new QwtScaleDraw());
            d->plot->setAxisScaleDraw(QwtPlot::yLeft, new QwtScaleDraw());
            d->picker->setTimeXAxis(false);
            if (d->zoomer) {
                d->zoomer->setTimeXAxis(false);
            }
            break;
        }
        default:
            break;
        }
    }
}

bool JCurveWidget::clearData(int index)
{
    Q_D(JCurveWidget);
    if (index == -1) {
        QVectorIterator<JCurve *> citer(d->curves);
        while (citer.hasNext()) {
            JCurve *curve = citer.next();
            curve->clear();
        }
    } else {
        if (index < 0 || index >= d->curves.count()) {
            return false;
        }

        //
        JCurve *curve = d->curves.at(index);
        if (curve == 0) {
            return false;
        }

        //
        curve->clear();
    }

    return true;
}

bool JCurveWidget::updateData(int index, const QVector<QPointF> &data)
{
    return updateData(curve(index), data);
}

bool JCurveWidget::updateData(JCurve *curve, const QVector<QPointF> &data)
{
    //
    if (curve == 0) {
        return false;
    }

    //
    curve->setSamples(data);

    return true;
}

bool JCurveWidget::updateData(int index, const QList<QPair<QTime, qreal> > &data)
{
    return updateData(curve(index), data);
}

bool JCurveWidget::updateData(JCurve *curve, const QList<QPair<QTime, qreal> > &data)
{
    //
    if (curve == 0) {
        return false;
    }

    Q_D(JCurveWidget);

    //
    QVector<QPointF> points;
#if 1
    QListIterator<QPair<QTime, qreal> > citer(data);
    if (d->axisXYType == AxisXY_Time_Value) {
        while (citer.hasNext()) {
            const QPair<QTime, qreal> &item = citer.next();
            points.append(QPointF(item.first.msecsSinceStartOfDay(), item.second));
        }
    } else if (d->axisXYType == AxisXY_Value_Time) {
        while (citer.hasNext()) {
            const QPair<QTime, qreal> &item = citer.next();
            points.append(QPointF(item.second, item.first.msecsSinceStartOfDay()));
        }
    } else {
        return false;
    }
#else
    for (int i = 0; i < 50; ++i) {
        //QPointF p((qreal) i, qSin(M_PI / 50 * i) * 100);
        //p.ry() += qrand() % 20;
        QPointF p(i, qrand() % 100);
        points.append(p);
    }
#endif
    curve->setSamples(points);

    return true;
}

QColor JCurveWidget::randColor(qreal opacity)
{
    return QColor(60 + qrand() % 190,
                  60 + qrand() % 190,
                  60 + qrand() % 190,
                  int(opacity * 255));
}

JSiftAreaEditor *JCurveWidget::siftAreaEditor()
{
    Q_D(JCurveWidget);
    return d->siftAreaEditor;
}

QList<QRectF> JCurveWidget::siftAreas() const
{
    Q_D(const JCurveWidget);
    return d->siftAreaEditor->siftAreas();
}

void JCurveWidget::setBaseLineSamples(const QList<QVector<QPointF> > &groupsData)
{
    Q_D(JCurveWidget);
    d->baseCurve->setSamples(groupsData);
}

void JCurveWidget::clearHotSpot()
{
    Q_D(JCurveWidget);
    d->siftAreaEditor->clearShape();
}

void JCurveWidget::addHotSpot(const QRectF &range, bool notify)
{
    Q_D(JCurveWidget);
    QPainterPath path;
    path.addRect(range);
    d->siftAreaEditor->addShape(path, "", notify);
}

void JCurveWidget::setOptionWidgetVisible(bool visible)
{
    Q_D(JCurveWidget);
    d->optionWidget->setVisible(visible);
}

void JCurveWidget::setZoomMode(bool checked)
{
    Q_D(JCurveWidget);
    d->optionWidget->setZoomMode(checked);
    if (checked && d->databaseEdit && d->optionWidget->isEditEnabled()) {
        clearHotSpot();
    }
}

void JCurveWidget::setSiftMode(bool checked)
{
    Q_D(JCurveWidget);
    d->optionWidget->setSiftMode(checked);
}

void JCurveWidget::setZoomModeVisible(bool visible)
{
    Q_D(JCurveWidget);
    d->optionWidget->setZoomModeVisible(visible);
}

void JCurveWidget::setSiftModeVisible(bool visible)
{
    Q_D(JCurveWidget);
    d->optionWidget->setSiftModeVisible(visible);
}

void JCurveWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
    Q_UNUSED(event);
    Q_D(JCurveWidget);
    if (!d->enableDbClick) {
        return;
    }

    d->showNormal = !d->showNormal;
    Q_EMIT doubleClicked(d->showNormal);
}
